package cn.iocoder.yudao.module.picturebook.service.book;

import cn.iocoder.yudao.module.picturebook.dal.dataobject.audio.AudioDO;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.bookcontext.BookContextDO;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.translation.TranslationDO;
import cn.iocoder.yudao.module.picturebook.dal.mysql.audio.AudioMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.bookcontext.BookContextMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.bookgather.BookGatherMapper;
import cn.iocoder.yudao.module.picturebook.dal.mysql.translation.TranslationMapper;
import cn.iocoder.yudao.module.picturebook.service.oss.OssServiceImpl;
import cn.iocoder.yudao.module.picturebook.utils.CustomMultipartFile;
import cn.iocoder.yudao.module.picturebook.utils.Jdk8AudioMergeUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

import cn.iocoder.yudao.module.picturebook.controller.admin.book.vo.*;
import cn.iocoder.yudao.module.picturebook.dal.dataobject.book.BookDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.picturebook.dal.mysql.book.BookMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.picturebook.enums.ErrorCodeConstants.*;

/**
 * 书籍信息 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class BookServiceImpl implements BookService {

    @Resource
    private BookMapper bookMapper;

    @Resource
    private BookContextMapper bookContextMapper;
    @Resource
    private TranslationMapper translationMapper;
    @Resource
    private AudioMapper audioMapper;
    @Resource
    private OssServiceImpl ossService;
    @Resource
    private BookGatherMapper bookGatherMapper;

    @Override
    @Cacheable(value = "book", key = "#bookId", unless = "#result == null")
    public BookDO selectById(Long bookId) {
        // 参数校验
        if (bookId == null) {
            return null;
        }

        return bookMapper.selectById(bookId);
    }


    @Override
    public Long createBook(BookSaveReqVO createReqVO) {
        // 参数校验
        if (createReqVO == null) {
            return null;
        }

        // 插入
        BookDO book = BeanUtils.toBean(createReqVO, BookDO.class);
        bookMapper.insert(book);

        // 添加空值检查
        if (book.getId() == null) {
            log.error("[createBook][bookId 创建失败，请稍后重试],其为空值");
            return null;
        }

        // 返回
        return book.getId();
    }

    @Override
    public void updateBook(BookSaveReqVO updateReqVO) {
        // 参数校验
        if (updateReqVO == null) {
            return;
        }
        if (updateReqVO.getId() == null) {
            return;
        }

        // 校验存在
        if (bookMapper.selectById(updateReqVO.getId()) == null) {
            log.error("[updateBook][bookId 更新失败，请稍后重试],bookId为空值");
            return;
        }
        // 更新
        BookDO updateObj = BeanUtils.toBean(updateReqVO, BookDO.class);
        bookMapper.updateById(updateObj);
    }

    @Override
    public void deleteBook(Long id) {
        // 参数校验
        if (id == null) {
            return;
        }

        // 校验存在
        if (bookMapper.selectById(id) == null) {
            return;
        }
        // 删除
        bookMapper.deleteById(id);
    }

    @Override
    public void deleteBookListByIds(List<Long> ids) {
        // 参数校验
        if (ids == null || ids.isEmpty()) {
            return;
        }

        // 删除
        bookMapper.deleteByIds(ids);
    }


    private void validateBookExists(Long id) {
        // 参数校验
        if (id == null) {
            return;
        }

        if (bookMapper.selectById(id) == null) {
            throw exception(BOOK_NOT_EXISTS);
        }
    }

    @Override
    public BookDO getBook(Long id) {
        // 参数校验
        if (id == null) {
            return null;
        }

        return bookMapper.selectById(id);
    }

    @Override
    public PageResult<BookDO> getBookPage(BookPageReqVO pageReqVO) {
        // 参数校验
        if (pageReqVO == null) {
            return PageResult.empty();
        }

        return bookMapper.selectPage(pageReqVO);
    }

    @Override
    public List<BookDO> getBookByLevel(Integer level) {
        // 参数校验
        if (level == null) {
            return Collections.emptyList();
        }

        return bookMapper.selectList(BookDO::getLevel, level);
    }

    @Override
    public List<BookDO> selectByIds(List<Long> collect) {
        // 参数校验
        if (collect == null || collect.isEmpty()) {
            return Collections.emptyList();
        }

        return bookMapper.selectByIds(collect);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long createPictureBook(Book createReqVO) {
        // 参数校验
        if (createReqVO == null) {
            return null;
        }
        if (createReqVO.getBookData() == null || createReqVO.getBookData().isEmpty()) {
            return null;
        }

        // 创建临时目录
        File tempDir = new File(System.getProperty("java.io.tmpdir"), "audio-merge-" + System.currentTimeMillis());
        if (!tempDir.exists()) {
            tempDir.mkdirs();
        }

        try {
            // 1. 下载音频到临时目录
            List<String> tempAudioPaths = new ArrayList<>();
            for (BookData data : createReqVO.getBookData()) {
                if (data != null && data.getAudioFile() != null) {
                    String tempPath = tempDir.getAbsolutePath() + File.separator + "temp-" + System.currentTimeMillis() + ".mp3";
                    try {
                        downloadAudioWithJava(data.getAudioFile(), tempPath);
                        tempAudioPaths.add(tempPath);
                    } catch (Exception e) {
                        // 记录日志但继续处理其他音频
                        log.error("[createPictureBook][downloadAudioWithJava({}) 下载音频失败，请稍后重试]", data.getAudioFile());
                    }
                }
            }

            // 2. 合并音频
            String mergedPath = tempDir.getAbsolutePath() + File.separator + "merged-" + System.currentTimeMillis() + ".mp3";
            try {
                Jdk8AudioMergeUtils.mergeAudiosToWav(tempAudioPaths, mergedPath);
            } catch (Exception e) {
                return null;
            }

            // 3. 上传到OSS
            File mergedFile = new File(mergedPath);
            CustomMultipartFile multipartFile = new CustomMultipartFile(mergedFile);
            String mergedAudioUrl = ossService.uploadFile(multipartFile);

            if (mergedAudioUrl == null) {
                return null;
            }

            // 第一步：创建绘本主记录
            BookDO bookDO = BookDO.builder()
                    .title(createReqVO.getBookName())
                    .author(createReqVO.getAuthor())
                    .publisher(createReqVO.getPublisher())
                    .coverUrl(createReqVO.getBookData().get(0).getImageFile())
                    .language(createReqVO.getBookType())
                    .level(String.valueOf(createReqVO.getLevel()))
                    .category(String.valueOf(createReqVO.getCategory()))
                    .build();

            bookMapper.createBook(bookDO);

            // 为绘本添加完整的录音
            AudioDO audioDO = AudioDO.builder()
                    .bookId(bookDO.getId())
                    .audioIdUrl(mergedAudioUrl)
                    .build();
            audioMapper.insert(audioDO);

            // 第二步：构建正确的JSON结构
            JSONArray mediaItems = new JSONArray();
            List<TranslationDO> translations = new ArrayList<>();

            for (int i = 0; i < createReqVO.getBookData().size(); i++) {
                BookData data = createReqVO.getBookData().get(i);
                if (data != null) {
                    // 构建媒体项
                    JSONObject item = new JSONObject();
                    item.put("audio_url", data.getAudioFile());
                    item.put("image_url", data.getImageFile());
                    item.put("currentPage", String.valueOf(i + 1));
                    mediaItems.add(item);

                    // 构建翻译项（修复重复设置bookId的问题）
                    TranslationDO translationDO = TranslationDO.builder()
                            .bookId(bookDO.getId())
                            .currentPage(i + 1)
                            .chinese(data.getCnText())
                            .english(data.getEnText())
                            .build();
                    translations.add(translationDO);
                }
            }

            // 构建完整JSON对象（包含media_list和total字段）
            JSONObject mediaListObject = new JSONObject();
            mediaListObject.put("media_list", mediaItems);
            mediaListObject.put("total", String.valueOf(createReqVO.getBookData().size()));

            // 批量插入翻译数据
            if (!translations.isEmpty()) {
                try {
                    translationMapper.insertBatch(translations);
                } catch (Exception e) {
                    // 批量插入失败，尝试逐个插入
                    for (TranslationDO translation : translations) {
                        try {
                            translationMapper.insert(translation);
                        } catch (Exception ex) {
                            // 单个插入也失败，记录日志继续
                            log.error("[createPictureBook][insertBatch 批量插入翻译数据失败，逐个插入失败，请稍后重试]", ex);
                        }
                    }
                }
            }

            // 第三步：保存绘本内容记录
            BookContextDO bookContextDO = BookContextDO.builder()
                    .bookId(String.valueOf(bookDO.getId()))
                    .context(mediaListObject.toJSONString())
                    .build();
            bookContextMapper.insert(bookContextDO);

            // 绘本集的数量加一
            bookMapper.updateTotal(bookDO.getLevel());

            return bookDO.getId();
        } catch (Exception e) {
            return null;
        } finally {
            // 确保删除临时文件和目录
            deleteTempFiles(tempDir);
        }
    }

    // 辅助方法：删除临时文件和目录
    private void deleteTempFiles(File dir) {
        if (dir == null || !dir.exists()) {
            return;
        }

        File[] files = dir.listFiles();
        if (files != null) {
            for (File file : files) {
                try {
                    file.delete();
                } catch (Exception e) {
                    // 删除失败，记录日志但继续
                    log.error("[deleteTempFiles][delete 删除文件失败，请稍后重试]", e);
                }
            }
        }
        try {
            dir.delete();
        } catch (Exception e) {
            // 删除目录失败，记录日志
            log.error("[deleteTempFiles][delete 删除目录失败，请稍后重试]", e);
        }
    }


    /**
     * 纯 Java 原生下载音频（不依赖 HttpClient，避免连接池问题）
     *
     * @param savePath 本地保存路径
     */
    private void downloadAudioWithJava(String audioUrl, String savePath) {
        // 参数校验
        if (audioUrl == null || savePath == null) {
            return;
        }

        HttpURLConnection connection = null;
        try {
            // 创建 URL 对象
            URL url = new URL(audioUrl);
            // 打开连接
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000); // 连接超时 5 秒
            connection.setReadTimeout(10000);   // 读取超时 10 秒

            // 检查响应状态（200 表示成功）
            if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
                return;
            }

            // 读取输入流并写入文件
            try (InputStream in = connection.getInputStream();
                 FileOutputStream out = new FileOutputStream(savePath)) {

                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }
        } catch (Exception e) {
            // 记录日志但不抛出异常
        } finally {
            if (connection != null) {
                try {
                    connection.disconnect(); // 关闭连接
                } catch (Exception e) {
                    // 关闭连接失败，记录日志
                    log.error("[downloadAudioWithJava][disconnect 关闭连接失败，请稍后重试]", e);
                }
            }
        }
    }
}